//
// Created by francklinson on 2021/7/12 AT 23:24.
//
//地上有一个m行n列的方格，从坐标 [0,0] 到坐标 [m-1,n-1] 。
//一个机器人从坐标 [0, 0] 的格子开始移动，它每次可以向左、右、上、下移动一格（不能移动到方格外），
//也不能进入行坐标和列坐标的数位之和大于k的格子。例如，当k为18时，机器人能够进入方格 [35, 37] ，
//因为3+5+3+7=18。但它不能进入方格 [35, 38]，因为3+5+3+8=19。请问该机器人能够到达多少个格子？
//
//来源：力扣（LeetCode）
//链接：https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof
//著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。

#include <vector>
#include <iostream>
#include <unordered_map>
#include <queue>

using namespace std;

class Solution {
public:
    /**
     * bfs搜索
     * @param m
     * @param n
     * @param k
     * @return
     */
    int movingCount(int m, int n, int k) {
        vector<vector<bool>> seen(m, vector<bool>(n, false));
        /// 先给出每个数对应的数位和hash
        unordered_map<int, int> bitSumMemory;
        for (int i = 0; i < max(m, n); ++i) {
            bitSumMemory[i] = bitSum(i);
        }
        queue<pair<int, int>> q;
        q.emplace(0, 0);
        seen[0][0] = true;
        int counter = 1;
        while (!q.empty()) {
            auto p = q.front();
            q.pop();
            int r = p.first;
            int c = p.second;
            for (auto &x:vector<pair<int, int>>{{r + 1, c},
                                                {r,     c + 1}}) {
                int nr = x.first, nc = x.second;
                if (nr >= 0 and nr < m and nc >= 0 and nc < n and not seen[nr][nc]) {
                    if (bitSumMemory[nr] + bitSumMemory[nc] <= k) {
                        ++counter;
                        seen[nr][nc] = true;
                        q.emplace(nr, nc);
                    }
                }
            }
        }
        return counter;
    }

    /**
     * 返回数位之和
     * @param x
     * @return
     */
    static int bitSum(int x) {
        int ret = 0;
        while (x != 0) {
            ret += x % 10;
            x /= 10;
        }
        return ret;
    }
};
class Solution2 {
    // 计算 x 的数位之和
    int get(int x) {
        int res=0;
        for (; x; x /= 10) {
            res += x % 10;
        }
        return res;
    }
public:
    int movingCount(int m, int n, int k) {
        if (!k) return 1;
        queue<pair<int,int> > Q;
        // 向右和向下的方向数组
        int dx[2] = {0, 1};
        int dy[2] = {1, 0};
        vector<vector<int> > vis(m, vector<int>(n, 0));
        Q.push(make_pair(0, 0));
        vis[0][0] = 1;
        int ans = 1;
        while (!Q.empty()) {
            auto [x, y] = Q.front();
            Q.pop();
            for (int i = 0; i < 2; ++i) {
                int tx = dx[i] + x;
                int ty = dy[i] + y;
                if (tx < 0 || tx >= m || ty < 0 || ty >= n || vis[tx][ty] || get(tx) + get(ty) > k) continue;
                Q.push(make_pair(tx, ty));
                vis[tx][ty] = 1;
                ans++;
            }
        }
        return ans;
    }
};

class Solution3 { // 递推方法
    int get(int x) {
        int res=0;
        for (; x; x /= 10){
            res += x % 10;
        }
        return res;
    }
public:
    int movingCount(int m, int n, int k) {
        if (!k) return 1;
        vector<vector<int> > vis(m, vector<int>(n, 0));
        int ans = 1;
        vis[0][0] = 1;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if ((i == 0 && j == 0) || get(i) + get(j) > k) continue;
                // 边界判断
                if (i - 1 >= 0) vis[i][j] |= vis[i - 1][j];
                if (j - 1 >= 0) vis[i][j] |= vis[i][j - 1];
                ans += vis[i][j];
            }
        }
        return ans;
    }
};



int main() {
    Solution2 solution;
    int m = 0, n = 0, k = 0;
    cout << "m:";
    cin >> m;
    cout << "n:";
    cin >> n;
    cout << "k:";
    cin >> k;
//    cout << solution.movingCount(3, 1, 0) << endl;
    cout << solution.movingCount(m, n, k) << endl;
    return 0;
}

